use core::arch::asm;

pub fn example3_2() {
    let mut ret0: usize;
    let mut ret1: usize;
    let mut ret2: usize;
    let mut ret3: usize;
    let mut ret4: usize;
    let mut ret5: usize;
    let mut ret6: usize;
    unsafe {
        asm!(
            "li t0, 0x80200000", // 把立即数加载到寄存器t0中。这里的地址是S模式下的，我们不能用0x80000000,因为它是在M模式下的。
            // 读取这个地址的内容会造成复位.
            "mv {0}, t0",  // 把寄存器t0的内容保存到ret变量中。
            "lb t1, (t0)", // 把t0寄存器的内容当作一个地址，加载这个地址指向的一个有符号字节
            "mv {1}, t1",
            "lb t1, 4(t0)", // 把t0寄存器的内容当作一个地址，加载这个地址+4后指向的一个有符号字节.
            "mv {2}, t1",
            "lbu t1, 4(t0)", // 把t0寄存器的内容当作一个地址，加载这个地址+4后指向的一个无符号字节.
            "mv {3}, t1",
            "li t0, 0x80200004",
            "lb t1, -4(t0)", // 把t0寄存器的内容当作一个地址，加载这个地址-4后指向的一个有符号字节.
            "mv {4}, t1",
            "li t0, 0x80200000", // 把t0寄存器的内容当作一个地址，加载这个地址指向的一个有符号64位整数.
            "ld t1, (t0)",
            "mv {5}, t1",
            "ld t1, 16(t0)",
            "mv {6}, t1",
            out(reg) ret0,
            out(reg) ret1,
            out(reg) ret2,
            out(reg) ret3,
            out(reg) ret4,
            out(reg) ret5,
            out(reg) ret6,
        );
    }
    println!("t0的内容为: 0x{:016x}", ret0);
    println!("0x80200000地址一个i8整数为: {}", ret1 as i8);
    println!("0x80200004地址一个i8整数为: {}", ret2 as i8);
    println!("0x80200004地址一个u8整数为: {}", ret3 as u8);
    println!("0x80200004 - 4地址一个i8整数为: {}", ret4 as i8);
    println!("0x80200000地址一个i64整数为: {}", ret5 as i64);
    println!("0x80200010地址一个i64整数为: {}", ret6 as i64);
}

pub fn example3_3() {
    let ret1: usize;
    let ret2: usize;
    unsafe {
        asm!(
            "lui t0, 0x80200",  // 0x80200(20位立即数)左移12位加载到t0寄存器中，符号位扩展。
            "mv {0}, t0",
            "lui t0, 0x40200",  // 0x40200(20位立即数)左移12位加载到t0寄存器中，符号位扩展
            "mv {1}, t0",
            out(reg) ret1,
            out(reg) ret2
        );
    }
    println!("ret1: 0x{:x}", ret1);
    println!("ret2: 0x{:x}", ret2);
}

pub fn example3_5() {
    let ret1: usize;
    let ret2: usize;
    unsafe {
        asm!(
            "auipc a5, 0x02",
            "mv {0}, a5",
            "lui a6, 0x02",
            "mv {1}, a6",
            out(reg) ret1,
            out(reg) ret2
        );
    }
    println!("ret1: 0x{:x}", ret1);
    println!("ret2: 0x{:x}", ret2);
}

static MY_TEST_DATA: u64 = 0x12345678abababab;

#[unsafe(no_mangle)]
#[inline(never)]
pub unsafe extern "C" fn example3_7() {
    let out1: usize;
    let out2: usize;
    let out3: usize;
    let out4: usize;
    let out5: usize;
    let out6: usize;
    unsafe {
        asm!("
            la t0, {data}
            lla t0, {data}
            li t0, 0x80200000
            mv {0}, t0
            li t0, 0x800000008a000000
            srai t1, t0, 1
            mv {1}, t1
            srli t1, t0, 1
            mv {2}, t1
            sraiw t1, t0, 1
            mv {3}, t1
            srliw t1, t0, 1
            mv {4}, t1
            slliw t1, t0, 1
            mv {5}, t1
        ",
            out(reg) out1,
            out(reg) out2,
            out(reg) out3,
            out(reg) out4,
            out(reg) out5,
            out(reg) out6,
            data = sym MY_TEST_DATA,
        );
    }
    println!("out is: 0x{:x}", out1);
    println!("out is: 0x{:x}", out2);
    println!("out is: 0x{:x}", out3);
    println!("out is: 0x{:x}", out4);
    println!("out is: 0x{:x}", out5);
    println!("out is: 0x{:x}", out6);
}
